package com.iss.supermarket.LoginUI;

import com.iss.supermarket.MainPage.MainPage;
import com.iss.supermarket.util.MessageWindow.MsgWin;
import com.iss.supermarket.util.entity.SpUser;
import com.iss.supermarket.util.repository.UserDao;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 成员变量
 * 构造器
 * 初始化方法
 * 内部类
 * 方法
 */

public class LoginUI extends JFrame {
    //单例模式
    private static LoginUI loginui;
    //定义组件
    private JLabel[] loginlabels;
    private JTextField[] loginTextFields;//loginTextFields[1]未使用
    private JPasswordField loginPasswordField;
    private JCheckBox PasswordVisible;
    private JButton button1;
    private JButton button2;
    private JButton button3;
    private JLabel imglabel;
    private String VerificationCode;
    private VerificationCodeGenerator vcg;
    private BufferedImage image;

    //连接数据库池
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:/spring_ioc.xml");
    UserDao userDao = ctx.getBean("UserDao", UserDao.class);

    //构造器
    public LoginUI(){
        super("用户登录");
        InitAssembly();
        InitUI();
    }

    //初始化界面，将组件添加到容器中
    private void InitUI(){
        //获得顶级容器
        Container container = getContentPane();
        //生成一个垂直的箱式容器
        Box verticalBox = Box.createVerticalBox();

        //一次添加组件
        JPanel jPanel1 = new JPanel();
        jPanel1.add(loginlabels[0]);
        jPanel1.add(loginTextFields[0]);
        verticalBox.add(jPanel1);

        JPanel jPanel2 = new JPanel();
        jPanel2.add(loginlabels[1]);
        jPanel2.add(loginPasswordField);
        jPanel2.add(PasswordVisible);
        verticalBox.add(jPanel2);

        JPanel jPanel3 = new JPanel();
        jPanel3.add(loginlabels[2]);
        jPanel3.add(loginTextFields[2]);
        jPanel3.add(imglabel);
        verticalBox.add(jPanel3);

        JPanel jPanel4 = new JPanel();
        jPanel4.add(button1);
        jPanel4.add(button2);
        jPanel4.add(button3);
        verticalBox.add(jPanel4);

        //向顶级容器中添加组件
        container.add(verticalBox);
        //设置组建的尺寸，居中显示，可视化
        setSize(500,400);
        setComponentInCenter(this);
        setVisible(true);
    }

    //初始化组件
    private void InitAssembly(){
        //实例化标签
        loginlabels = new JLabel[3];
        loginlabels[0] = new JLabel("账号");
        loginlabels[1] = new JLabel("密码");
        loginlabels[2] = new JLabel("验证码");
        for(int i=0;i<loginlabels.length;++i){
            //设置标签的对齐方式
            loginlabels[i].setHorizontalAlignment(SwingConstants.LEFT);
            //设置标签的尺寸
            loginlabels[i].setPreferredSize(new Dimension(100,20));
            //设置标签字体格式
            loginlabels[i].setFont(new Font("微软雅黑",Font.PLAIN,14));
        }

        //实例化文本框
        loginTextFields = new JTextField[3];
        for(int i=0;i<3;++i) {
            loginTextFields[i] = new JTextField();
            loginTextFields[i].setHorizontalAlignment(SwingConstants.CENTER);
            if(i == 2)
                loginTextFields[i].setPreferredSize(new Dimension(200,25));
            else
                loginTextFields[i].setPreferredSize(new Dimension(300,25));
            loginTextFields[i].setFont(new Font("微软雅黑",Font.PLAIN,14));
        }
        //测试
        loginTextFields[0].setText("13915968208");
        //实例化密码框
        loginPasswordField = new JPasswordField();
        //设置对齐方式
        loginPasswordField.setHorizontalAlignment(SwingConstants.CENTER);
        //设置组件大小
        loginPasswordField.setPreferredSize(new Dimension(200,25));
        //***测试***//
        loginPasswordField.setText("123456");
        //设置字体格式
        loginPasswordField.setFont(new Font("微软雅黑",Font.PLAIN,14));
        //获得默认的回显字符
        char defaultEchoChar = loginPasswordField.getEchoChar();
        //实例化密码是否可见的复选框
        PasswordVisible = new JCheckBox();
        PasswordVisible.setText("显示密码");
        PasswordVisible.setPreferredSize(new Dimension(100,25));
        //lambda表达式
        PasswordVisible.addItemListener(e -> {
            //lambda表达式
            if(e.getStateChange() == ItemEvent.SELECTED){
                //设置密码可见
                loginPasswordField.setEchoChar((char)0);
            }else if(e.getStateChange() == ItemEvent.DESELECTED){
                loginPasswordField.setEchoChar(defaultEchoChar);
            }
        });

        //实例化验证码类，采用单例方法
        vcg = VerificationCodeGenerator.getVerificationCodeGenerator();
        image = vcg.createImage(100,50,2);
        imglabel = new JLabel(new ImageIcon(image));
        //获得生成验证码
        VerificationCode = vcg.getVerificationCode();
        //***测试***//
        loginTextFields[2].setText(VerificationCode);
        System.out.println(VerificationCode);

        //实例化按钮，注册监听，设置字体格式
        button1 = new JButton("注册");
        button1.addActionListener(new ButtonAction());
        button1.setPreferredSize(new Dimension(100,30));
        button1.setFont(new Font("黑体",Font.PLAIN,14));
        button2 = new JButton("登录");
        button2.addActionListener(new ButtonAction());
        button2.setPreferredSize(new Dimension(100,30));
        button2.setFont(new Font("黑体",Font.PLAIN,14));
        button3 = new JButton("点击更换验证码");
        button3.addActionListener(new ButtonAction());
        button3.setPreferredSize(new Dimension(180,30));
        button3.setFont(new Font("黑体",Font.PLAIN,14));

        //鼠标的事件监听，用于将变红的标签恢复成黑色
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                loginlabels[0].setForeground(Color.BLACK);
                loginlabels[1].setForeground(Color.BLACK);
                loginlabels[2].setForeground(Color.black);
            }
        });
    }

    //初始化检查类，用于检查用户输入的类容是否合法
    class LoginCheck{
        //用于匹配的字符串
        private static final String MOBILE_REGEX_EXP = "^((13[0-9])|(14[5,7,9])|(15[0-3,5-9])|(166)|(17[0-9])|(18[0-9])|(19[1,8,9]))\\d{8}";
        private static final String EMAIL_REGEX_EXP = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";

        public LoginCheck(){}

        private boolean checkVerificationCode(){
            if("".equals(loginTextFields[2].getText())){
                MsgWin msgWin = new MsgWin("请输入验证码");
                return false;
            }else if(!VerificationCode.equals(loginTextFields[2].getText())){
                MsgWin msgWin = new MsgWin("验证码错误");
                return false;
            }
            return true;
        }
        
        private boolean cheakMobileFormat(){
            //为空则返回假
            if("".equals(loginTextFields[0].getText())){
                return false;
            }
            //正则表达式匹配手机号码的格式
            Pattern pattern = Pattern.compile(MOBILE_REGEX_EXP);
            Matcher matcher = pattern.matcher(String.valueOf(loginTextFields[0].getText()));
            if(!matcher.matches()){
                return false;
            }
            return  true;
        }

        private boolean checkEmailFormat(){
            //为空则返回假

            if("".equals(loginTextFields[0].getText())){
                return false;
            }
            //正则表达式匹配邮箱的格式
            Pattern pattern = Pattern.compile(EMAIL_REGEX_EXP);
            Matcher matcher = pattern.matcher(loginTextFields[0].getText());
            if(!matcher.matches()){
                return false;
            }
            return true;
        }
    }

    //按钮的事件监听类
    private class ButtonAction implements ActionListener{
        @Override
        public void actionPerformed(ActionEvent e) {
            if("注册".equals(e.getActionCommand())) {
                RegisterUI registerUI = RegisterUI.getRegisterUI();
                registerUI.setVisible(true);

                loginui.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
                loginui = null;
                dispose();
                /**
                 * dispose是 java.awt.Windows类的方法，它的作用是销毁程序中指定的图形界面资源，对数据资源不产生影响，所以当我们在SWing或是AWT中的图形界面组件时如果调用它，组建内的数据对象不会消失，只有在这些数据资源其他地方没有再使用后才会由垃圾回收机制处理掉。
                 */
                //HIDE_ON_CLOSE隐藏窗体，不释放资源
                //DO_NOTHING_ON_CLOSE对窗体不执行任何关闭操作
                //DISPOSE_ON_CLOSE关闭当前窗体，释放当前窗体的资源
                //EXIT_ON_CLOSE使用 System.exit 方法退出应用程序，会退出所有窗体
                //System.exit(0)退出整个程序
            }else if("登录".equals(e.getActionCommand())){
                //去除字符串首位的空格
                loginTextFields[0].setText(loginTextFields[0].getText().trim());
                //生成检查类
                LoginCheck loginCheck = new LoginCheck();
                //定义一个SpUser用于数据库查询
                SpUser spUser = new SpUser();

                //用户登录时可以用用户名/手机号码/电子邮箱登录
                //所以对于用户的输入检查，判断采用哪一种方式登录
                if(loginCheck.cheakMobileFormat()){
                    spUser = userDao.queryUserInfoByMobile(loginTextFields[0].getText());
                }else if(loginCheck.checkEmailFormat()){
                    spUser = userDao.queryUserInfoByEmail(loginTextFields[0].getText());
                }else if(!"".equals(loginTextFields[0].getText())){
                    spUser = userDao.queryUserInfoByName(loginTextFields[0].getText());
                }else{
                    //检查失败，返回提示信息
                    MsgWin msgWin = new MsgWin("账号格式错误");
                }

                //检查用户是否存在
                if(spUser == null){
                    //用户不存在，将账号设置为红色用于提醒用户，同时返回提示信息
                    loginlabels[0].setForeground(Color.red);
                    MsgWin msgWin = new MsgWin("用户不存在");
                }else{
                    //用户存在，判断用户是否被锁定（即被删除，采用软删除），0表示为被锁定，1表示被锁定
                    if(spUser.getDelFlag() == 0){
                        //检测用户输入的密码和数据库中的用户密码是否一致
                        //String.valueOf(loginPasswordField.getPassword())获得字符串格式下的输入的密码，getPassword()返回char[]
                        if (!(spUser.getPassword().trim()).equals(String.valueOf(loginPasswordField.getPassword()))){
                            //密码不一致，密码标签设置为红色用于提醒用户，清空密码，返回提示信息
                            loginlabels[1].setForeground(Color.red);
                            loginPasswordField.setText("");
                            MsgWin msgWin = new MsgWin("密码错误");
                        }else{
                            //检测验证码是否正确
                            if (!loginCheck.checkVerificationCode()){
                                //验证码不正确，验证码标签设置为红色提醒用户，清空验证码，返回提示信息
                                loginlabels[2].setForeground(Color.red);
                                loginTextFields[2].setText("");
                                MsgWin msgWin = new MsgWin("验证码错误");
                            }else{
                                //所有验证均通过，生成主页面，查询到的用户作为参数传递
                                MainPage mainPage = new MainPage(spUser);
                                //关闭登录页面
                                dispose();
                            }
                        }
                    }else{
                        //用户被锁定返回提示信息
                        MsgWin msgWin = new MsgWin("用户已锁定");
                    }
                }

            }else if("点击更换验证码".equals(e.getActionCommand())){
                //调用验证码类生成一个验证码图片
                BufferedImage image = vcg.createImage(100,50,2);
                //获取生成的验证码字符串
                VerificationCode = vcg.getVerificationCode();
                //改变UI中的验证码图片
                imglabel.setIcon(new ImageIcon(image));
            }
        }
    }

    //单例方法
    public static synchronized LoginUI getLoginUI(){
        if(loginui == null)
            loginui = new LoginUI();
        return loginui;
    }

    //设置组件对于屏幕居中
    private void setComponentInCenter(Component component){
        //获得组件尺寸
        Dimension UISIZAE = component.getSize();
        //获得屏幕尺寸
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        //如果组件高度大于屏幕高度，则组件和屏幕同高度
        if (UISIZAE.height > screenSize.height)
            UISIZAE.height = screenSize.height;
        //如果组件宽度大于屏幕狂赌，则组件和屏幕同宽度
        if (UISIZAE.width > screenSize.width)
            UISIZAE.width = screenSize.width;
        //设置组件的位置
        component.setLocation((screenSize.width - UISIZAE.width) / 2, (screenSize.height - UISIZAE.height) / 2);
    }

    public static void main(String[] args) {
        LoginUI loginUI = LoginUI.getLoginUI();
    }
}